fix: fix application tray crash due to parent-child ownership and null pointer issues#465
Conversation
pointer issues 1. Fix crash in DDEindicatorTrayProtocol by using window() instead of parent() for event filter and content updates 2. Add null pointer checks in DDEindicatorTrayProtocol event filter 3. Fix crash in SniTrayProtocolHandler by using window() instead of parent() and adding null checks 4. Fix tooltip removal order in TrayPlugin to avoid dangling pointer references 5. Fix double-delete crash in TrayWidget by not setting handler as child widget 6. Add null handler checks in TrayWidget showEvent and paintEvent Log: Fixed application tray crashes when tray items are added/removed Influence: 1. Test adding and removing multiple tray items 2. Test tray indicator protocol operations 3. Test sni protocol tray operations 4. Test tray widget paint and show events 5. Test tray icon updates and tooltip display 6. Test application tray with various indicator types feat: 修复应用托盘因父子关系和空指针导致的崩溃问题 1. 修复 DDEindicatorTrayProtocol 中,使用 window() 替代 parent() 进行事 件过滤和内容更新 2. 在 DDEindicatorTrayProtocol 的事件过滤器中添加空指针检查 3. 修复 SniTrayProtocolHandler 中,使用 window() 替代 parent() 并添加空 指针检查 4. 修复 TrayPlugin 中 tooltip 移除顺序,避免悬空指针引用 5. 修复 TrayWidget 中不将 handler 设置为子控件导致的二次删除崩溃 6. 在 TrayWidget 的 showEvent 和 paintEvent 中添加 handler 空指针检查 Log: 修复添加/移除托盘项时应用托盘崩溃的问题 Influence: 1. 测试添加和移除多个托盘项 2. 测试托盘指示协议操作 3. 测试 sni 协议托盘操作 4. 测试托盘控件的绘制和显示事件 5. 测试托盘图标更新和提示信息显示 6. 测试各种指示类型下的应用托盘功能
Reviewer's GuideFixes crashes in the application tray by removing conflicting QObject parent ownership for tray protocol handlers, switching to window-based lookups instead of parent() in event filters, and adding null checks and cleanup ordering for tooltip and window handle usage. Sequence diagram for tray item removal and tooltip cleanupsequenceDiagram
participant TrayPlugin
participant TooltipMap as m_tooltip
participant ProxyInterface as m_proyInter
participant WidgetMap as m_widget
TrayPlugin->>TooltipMap: remove(id)
TrayPlugin->>ProxyInterface: itemRemoved(TrayPlugin,id)
TrayPlugin->>WidgetMap: value(id)
TrayPlugin->>WidgetMap: remove(id)
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
deepin pr auto review你好!我是CodeGeeX。我已仔细审查了你提供的Git Diff。本次代码变更主要涉及对Qt控件生命周期的修正、空指针防护、悬空指针清理顺序的调整以及版权声明的格式化。 整体来看,这次修改质量很高,修复了几个非常关键的潜在Bug(如双重释放、空指针解引用、悬空指针访问等)。以下是针对各个修改点的详细审查意见: 1. 语法与逻辑👍 亮点:移除 👍 亮点:调整
void TrayWidget::showEvent(QShowEvent* event)
{
Q_UNUSED(event)
if (!m_handler)
return;
m_handler->setWindow(window());
window()->installEventFilter(m_handler); // 潜在风险
window()->setMouseTracking(true);
}虽然增加了 void TrayWidget::showEvent(QShowEvent* event)
{
Q_UNUSED(event)
if (!m_handler)
return;
QWindow *win = window();
if (!win)
return;
m_handler->setWindow(win);
win->installEventFilter(m_handler);
win->setMouseTracking(true);
}2. 代码质量👍 亮点:使用 📝 建议: 3. 代码性能👍 逻辑正确,无性能劣化
4. 代码安全👍 亮点:修复多处空指针解引用漏洞
auto *win = window()->windowHandle();
if (!win)
return false;
auto plugin = Plugin::EmbedPlugin::get(win);
auto geometry = plugin->pluginPos(); // 潜在风险增加了 auto *win = window()->windowHandle();
if (!win)
return false;
auto plugin = Plugin::EmbedPlugin::get(win);
if (!plugin)
return false;
auto geometry = plugin->pluginPos();总结本次 Diff 是一次高质量的缺陷修复,核心逻辑非常正确,显著提升了插件的稳定性和安全性。建议采纳上述关于 |
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- In TrayWidget::showEvent you guard against a null m_handler but still unconditionally call window()->installEventFilter and window()->setMouseTracking; consider also checking that window() is non-null before using it to avoid potential crashes during early lifecycle.
- In SniTrayProtocolHandler::eventFilter, window()->windowHandle() is called before any null check on window(); if window() can be null in some cases, add a guard for window() itself before dereferencing it to prevent rare null-dereference crashes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In TrayWidget::showEvent you guard against a null m_handler but still unconditionally call window()->installEventFilter and window()->setMouseTracking; consider also checking that window() is non-null before using it to avoid potential crashes during early lifecycle.
- In SniTrayProtocolHandler::eventFilter, window()->windowHandle() is called before any null check on window(); if window() can be null in some cases, add a guard for window() itself before dereferencing it to prevent rare null-dereference crashes.
## Individual Comments
### Comment 1
<location path="plugins/application-tray/sniprotocolhandler.cpp" line_range="331" />
<code_context>
- auto widget = static_cast<QWidget*>(parent());
- auto plugin = Plugin::EmbedPlugin::get(widget->window()->windowHandle());
+ auto *win = window()->windowHandle();
+ if (!win)
+ return false;
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against a potential nullptr from window() before calling windowHandle().
`window()` might return `nullptr` depending on when this is called. To avoid a potential null dereference, first store the result in a local variable, check it, and only then access `windowHandle()`, e.g. `auto *w = window(); if (!w) return false; auto *win = w->windowHandle();` to match the defensive pattern used for `win` below.
</issue_to_address>
### Comment 2
<location path="plugins/application-tray/traywidget.cpp" line_range="48-55" />
<code_context>
void TrayWidget::showEvent(QShowEvent* event)
{
Q_UNUSED(event)
+ if (!m_handler)
+ return;
+
m_handler->setWindow(window());
window()->installEventFilter(m_handler);
window()->setMouseTracking(true);
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Avoid repeatedly installing the same event filter on each showEvent.
`window()->installEventFilter(m_handler)` runs on every show, and Qt will invoke the filter once per installation, causing duplicate handling per event. Please ensure the filter is installed only once (e.g., track an `installed` flag, detect `window()` changes, or move installation to a place that runs only once when the window becomes available).
Suggested implementation:
```cpp
void TrayWidget::showEvent(QShowEvent* event)
{
Q_UNUSED(event)
if (!m_handler)
return;
QWidget *w = window();
if (!w)
return;
m_handler->setWindow(w);
if (m_lastWindowWithFilter != w) {
w->installEventFilter(m_handler);
m_lastWindowWithFilter = w;
}
w->setMouseTracking(true);
```
1. In `traywidget.h`, add a member to track the last window where the filter was installed, e.g.:
`QWidget *m_lastWindowWithFilter = nullptr;`
2. Ensure `m_lastWindowWithFilter` is initialized to `nullptr` in the constructor if in-class initialization is not used.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: 18202781743, BLumia The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
/forcemerge |
|
This pr force merged! (status: blocked) |
问题描述
应用程序托盘在 SNI (StatusNotifierItem) 托盘项注销时崩溃。
根本原因
SniTrayProtocolHandler同时被QSharedPointer和 QObject 父子关系管理,导致双重删除m_tooltip中存储的 widget 指针在 handler 销毁后变成悬空指针eventFilter中使用parent()获取 widget,但移除setParent(this)后返回错误对象修复内容
traywidget.cpp
m_handler->setParent(this)避免双重生命周期管理showEvent和paintEvent中添加m_handler空指针检查sniprotocolhandler.cpp
eventFilter中将parent()替换为window()windowHandle()的空指针检查ddeindicatortrayprotocol.cpp
updateContent中将q->parent()替换为q->window()eventFilter中将parent()替换为window(),添加空指针检查trayplugin.cpp
removelambda 中,先清理m_tooltip,再调用itemRemoved,避免访问悬空指针测试
修复后需要验证:
🤖 Generated with Claude Code
Summary by Sourcery
Prevent crashes and dangling pointers in the application tray by aligning tray handler ownership with Qt windowing semantics and cleaning up tooltip references safely.
Bug Fixes:
Enhancements: